using System;

using Microsoft.SPOT.Hardware;
using Microsoft.SPOT.Time;
using Microsoft.SPOT.Net.NetworkInformation;

using OST.Shared;
using OST.Shared.SharedTypes;

using mfLogger;
using mfLogger.NetworkAppenders;
using mfRCF.Core;
using mfRCF.netmf;
using System.Threading;

namespace OST.Persistence.Extensions
{
    public static class ConfigurationExtensions
    {
        /// <summary>
        /// wrapper-property 4 logging
        /// </summary>
        private static ILoggerAppender Logger
        {
            get
            {
                return mfLogger.mfLogger.Instance;
            }
        }

        /// <summary>
        /// extension method for <see cref="LoggingConfiguration"/> to execute an instance
        /// </summary>
        /// <param name="loggingConfiguration">specified logging-config-instance</param>
        public static void ApplyLogging(this LoggingConfiguration loggingConfiguration)
        {
            try
            {
                if (loggingConfiguration == null)
                    throw new OSTException("no logging-config available");

                if (mfLogger.mfLogger.Instance.MessageCapacity != loggingConfiguration.Size)
                {
                    mfLogger.mfLogger.Instance.MessageCapacity = loggingConfiguration.Size;
                }

                var numOfAppenders = 0;

                if (loggingConfiguration.ToDebug) numOfAppenders++;
                if (loggingConfiguration.ToFile) numOfAppenders++;
                if (loggingConfiguration.ToRss) numOfAppenders++;

                mfLogger.mfLogger.Instance.Appenders.Clear();

                if (loggingConfiguration.ToDebug)
                {
                    mfLogger.mfLogger.Instance.Appenders.Add(new mfDebugAppender());
                }
                if (loggingConfiguration.ToFile)
                {
                    mfLogger.mfLogger.Instance.Appenders.Add(new mfPeriodicFileAppender(mfLogger.mfLogger.Instance.Name));
                }
                if (loggingConfiguration.ToRss)
                {
                    mfLogger.mfLogger.Instance.Appenders.Add(new mfRssAppender("/rss"));
                }

                mfLogger.mfLogger.Instance.Level = loggingConfiguration.Level;

                Logger.Debug("logging-config applied");
            }
            catch (Exception ex)
            {
                Logger.Error(new OSTException("error in ApplyLogging(): " + ex.Message, ex));
            }
        }

        /// <summary>
        /// extension method for <see cref="TimeServiceConfiguration"/> to execute an instance
        /// </summary>
        /// <param name="timeServiceConfig">specified time-service-config-instance</param>
        public static void ApplyTimeService(this TimeServiceConfiguration timeServiceConfig)
        {
            try
            {
                if (timeServiceConfig == null)
                    throw new OSTException("no time-service-config available");

                if (!timeServiceConfig.UseNtp)
                {
                    Utility.SetLocalTime(timeServiceConfig.Value);
                }
                else
                {
                    try
                    {
                        Logger.Debug("try to synchronize time over ntp...");

                        TimeService.SetTimeZoneOffset(timeServiceConfig.TimeZone * 60);

                        TimeServiceSettings settings = new TimeServiceSettings();

                        var arrIpSeg = timeServiceConfig.NtpServer.Split(new char[] { '.' }, 4);

                        settings.PrimaryServer = new byte[] { Convert.ToByte(arrIpSeg[0])
                        , Convert.ToByte(arrIpSeg[1])
                        , Convert.ToByte(arrIpSeg[2])
                        , Convert.ToByte(arrIpSeg[3]) };

                        var checkSumBefore = DateTime.Now.Year + DateTime.Now.Month + DateTime.Now.Day;

                        TimeService.Settings = settings;
                        TimeService.Start();

                        TimeService.UpdateNow(10000);
                        Thread.Sleep(3000);//wait to apply

                        var checkSumAfter = DateTime.Now.Year + DateTime.Now.Month + DateTime.Now.Day;

                        if (checkSumBefore == checkSumAfter)
                        {
                            throw new OSTException("ntp failed, DateTime didn't changed");
                        }

                        //Set ntp-datetime in config-instance, no explicit persistence! ...maybe done by user, later?!
                        //...but no this is the reference for /system/uptime-REST-path
                        timeServiceConfig.Value = DateTime.Now;

                        Logger.Debug("...time over ntp synchronized");
                    }
                    catch (Exception ex)
                    {
                        Logger.Error(ex);
                        Logger.Warning("ntp error, 'ManualDateTimeValue' will be used");

                        Utility.SetLocalTime(timeServiceConfig.Value);
                    }
                }

                Logger.Debug("Time-Service applied");
            }
            catch (Exception ex)
            {
                Logger.Error(new OSTException("error in ApplyTimeService(): " + ex.Message, ex));
            }
        }

        /// <summary>
        /// extension method for <see cref="EthernetConfiguration"/> to execute an instance
        /// </summary>
        /// <param name="ethernetConfig">specified ethernet-config-instance</param>
        public static void ApplyEthernet(this EthernetConfiguration ethernetConfig)
        {
            try
            {
                if (ethernetConfig == null)
                    throw new OSTException("no static-config available");

                var netIOs = NetworkInterface.GetAllNetworkInterfaces();

                foreach (var netIO in netIOs)
                {
                    if (ethernetConfig.UseStatic)
                    {
                        netIO.EnableStaticIP(ethernetConfig.IP, ethernetConfig.Mask, ethernetConfig.Gateway);
                        netIO.EnableStaticDns(new string[] { ethernetConfig.Dns });
                        Logger.Info("Network on static-IP: " + netIO.IPAddress);
                    }
                    else
                    {
                        netIO.EnableDhcp();
                        Logger.Info("Network on dynamic-IP: " + netIO.IPAddress);
                    }
                    break;//just the first net-io
                }

                //initialize & start rcf
                Logger.Debug("rcf initializing");
                var rcfPlattformProvider = new mfRcfPlattformProvider();
                mfRcf.Instance.PlattformProvider = rcfPlattformProvider;
                mfRcf.Instance.Start();
                Logger.Debug("rcf initialized");

                Logger.Debug("ethernet-configuration applied");
            }
            catch (Exception ex)
            {
                Logger.Error(new OSTException("error in ApplyEthernet(): " + ex.Message, ex));
            }
        }

    }
}
